#!python --version
상관계수를 추론하고자 할 때는 각 집단에 따른 검정 가설이 필요하다.
- 귀무가설: 두 변수의 직선 관계는 유의하지 않다. p == 0
- 대립가설: 두 변수의 직선 관계는 유의하다. p =/= 0
단, n > 20인 대표본 집단에서는 정규분포 가정이 필요하지 않다.
[ 보스턴 517번가 주택가격 예측 예제 풀이 ]
데이터 설명
from sklearn.datasets import load_boston
import pandas as pd
boston = load_boston()
df = pd.DataFrame(boston.data)
df.columns = boston.feature_names
df['PRICE'] = boston.target
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 506 entries, 0 to 505 Data columns (total 14 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 CRIM 506 non-null float64 1 ZN 506 non-null float64 2 INDUS 506 non-null float64 3 CHAS 506 non-null float64 4 NOX 506 non-null float64 5 RM 506 non-null float64 6 AGE 506 non-null float64 7 DIS 506 non-null float64 8 RAD 506 non-null float64 9 TAX 506 non-null float64 10 PTRATIO 506 non-null float64 11 B 506 non-null float64 12 LSTAT 506 non-null float64 13 PRICE 506 non-null float64 dtypes: float64(14) memory usage: 55.5 KB
from matplotlib import pyplot as plt
import plotly.express as px
import pandas as pd
fig = px.scatter(df, x='PTRATIO', y = 'PRICE', color = 'CHAS',
marginal_x = 'box', marginal_y = 'histogram', trendline = 'ols')
fig.show()
( 산점도로 알 수 있는 점 )
# 상관계수로 확인
import scipy.stats as stats
stats.pearsonr(df['PRICE'], df['PTRATIO'])
# 피어슨 상관계수 -0.51
(-0.5077866855375619, 1.609509478472518e-34)
stats.spearmanr(df['PRICE'], df['PTRATIO'])
# 스피어맨 상관계수 -0.56
# 산점도에서 보면 적합 직선을 벗어난 이상치가 존재할 때 스피어맨 상관계수의 크기가 크다.
SpearmanrResult(correlation=-0.5559046822691174, pvalue=2.224971669470621e-42)
stats.kendalltau(df['PRICE'],df['PTRATIO'])
# 켄달타우 상관계수 -0.399
KendalltauResult(correlation=-0.39878862213643146, pvalue=7.610857660296044e-38)
( 상관 계수 )
: 교사 일인당 학생수가 많을수록 주택 가격은 떨어진다.
df.groupby('CHAS')[['PRICE','PTRATIO']].corr(method = 'pearson')
| PRICE | PTRATIO | ||
|---|---|---|---|
| CHAS | |||
| 0.0 | PRICE | 1.000000 | -0.540655 |
| PTRATIO | -0.540655 | 1.000000 | |
| 1.0 | PRICE | 1.000000 | -0.063987 |
| PTRATIO | -0.063987 | 1.000000 |
( 상관계수 해석 )
( pairplot = 산점도 행렬을 사용하는 이유 )
import seaborn as sns
import matplotlib.pyplot as plt
sns.pairplot(df.iloc[:,[0,1,2,10,13]],kind = 'reg',diag_kind = 'kde')
<seaborn.axisgrid.PairGrid at 0x154e5ed6eb0>
df.iloc[:,[0,1,2,10,13]].corr(method = 'pearson')
| CRIM | ZN | INDUS | PTRATIO | PRICE | |
|---|---|---|---|---|---|
| CRIM | 1.000000 | -0.200469 | 0.406583 | 0.289946 | -0.388305 |
| ZN | -0.200469 | 1.000000 | -0.533828 | -0.391679 | 0.360445 |
| INDUS | 0.406583 | -0.533828 | 1.000000 | 0.383248 | -0.483725 |
| PTRATIO | 0.289946 | -0.391679 | 0.383248 | 1.000000 | -0.507787 |
| PRICE | -0.388305 | 0.360445 | -0.483725 | -0.507787 | 1.000000 |
주택가격과 상관관계가 유의한지는 유의성 검정을 실시하거나 회귀분석을 통해 주택 가격에 유의한 영향을 주는 변수를 검정해보아야 한다.
*오차항 가정이 필요한 이유
등분산성: 오차항의 분산은 동일하다. 분산이 일정하다는 가정의 주어진 설명변수 값에서 관측되는 Y의 값이 분산이 일정하다는 의미와 같다. 분산이 다를 경우 설정된 회귀 모형이 적절함에도 불구, 관측치가 직선에 모여있지 않게 된다.
*즉, 이상치 발생은 직선의 적합성 결여 혹은 분산이 크므로 벗어나는지 알 수 없어 이상치 진단이 어려워진다.
### 산점도
from matplotlib import pyplot as plt
import plotly.express as px
import pandas as pd
fig = px.scatter(df, x = 'PTRATIO', y = 'PRICE', marginal_x = 'box', marginal_y = 'histogram', trendline = 'ols')
fig.show()
### 회귀계수 추정
import statsmodels.api as sm
y = df['PRICE']
X = sm.add_constant(df['PTRATIO'])
fit = sm.OLS(y, X).fit()
print(fit.summary())
OLS Regression Results
==============================================================================
Dep. Variable: PRICE R-squared: 0.258
Model: OLS Adj. R-squared: 0.256
Method: Least Squares F-statistic: 175.1
Date: Thu, 13 Apr 2023 Prob (F-statistic): 1.61e-34
Time: 00:57:40 Log-Likelihood: -1764.8
No. Observations: 506 AIC: 3534.
Df Residuals: 504 BIC: 3542.
Df Model: 1
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 62.3446 3.029 20.581 0.000 56.393 68.296
PTRATIO -2.1572 0.163 -13.233 0.000 -2.477 -1.837
==============================================================================
Omnibus: 92.924 Durbin-Watson: 0.725
Prob(Omnibus): 0.000 Jarque-Bera (JB): 191.444
Skew: 1.001 Prob(JB): 2.68e-42
Kurtosis: 5.252 Cond. No. 160.
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
C:\Anaconda3\lib\site-packages\statsmodels\tsa\tsatools.py:142: FutureWarning: In a future version of pandas all arguments of concat except for the argument 'objs' will be keyword-only
산점도에서는 약한 직선관계를 보였으나 ols 분석 결과를 해석해 보면 학생-교사의 비율을 보스턴 주택가격을 매우 유의하게 설명한다.(예측변수의 유의성 검정 확률은 0.000으로 0.001보다 작다.) 그러나 설명 비율은 25.8% 밖에 되지 않기에 주택가격을 설명할 다른예측 변수의 도출이 필요하다.
### 최종 모형 진단
### 잔차 진단
import seaborn as sns
import matplotlib.pyplot as plt
sns.residplot(fit.fittedvalues, fit.resid_pearson, lowess= True)
plt.title(' (yhat vs standard_res) 산점도 ')
plt.axhline(2)
plt.axhline(-2)
plt.show()
C:\Anaconda3\lib\site-packages\seaborn\_decorators.py:36: FutureWarning: Pass the following variables as keyword args: x, y. From version 0.12, the only valid positional argument will be `data`, and passing other arguments without an explicit keyword will result in an error or misinterpretation. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:240: RuntimeWarning: Glyph 49328 missing from current font. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:240: RuntimeWarning: Glyph 51216 missing from current font. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:240: RuntimeWarning: Glyph 46020 missing from current font. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:203: RuntimeWarning: Glyph 49328 missing from current font. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:203: RuntimeWarning: Glyph 51216 missing from current font. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:203: RuntimeWarning: Glyph 46020 missing from current font.
*그러나 변수들간의 관계가 복잡하게 얽힌 경우 통합적 선형성 검정분석 방법이 필요하다.
### 선형성 진단
import statsmodels.stats.api as sms
sms.linear_harvey_collier(fit)
# 귀무가설: 회귀무형은 선형이 적절하다.
# 대립가설: 선형모형이 아니다.
# 유의확률이 매우 높아 선형 회귀 모형이 적절하다. (0.963)
Ttest_1sampResult(statistic=-0.04531878810594354, pvalue=0.963871233587935)
### 오차 가정 진단
from scipy.stats import shapiro
shapiro(fit.resid) [0:2]
# 귀무가설: 데이터는 정규분포를 따른다.
# 대립가설: 정규분포를 따르지 않는다.
# 유의확률이 매우 작아 귀무가설 기각.
# 산점도에서 확인할 수 있듯이 목표변수가 약간 좌로 치우쳐져 있었음. 때문에 잔자도 정규준포를 따르지 아니한다.
# 대표본의 경우라면 정규성 가정을 반드시 만족할 필요가 없다.
(0.942956268787384, 4.966516564328116e-13)
### 등분산성 검정
import statsmodels.stats.api as sms
sms.het_goldfeldquandt(fit.resid, fit.model.exog)[0:2]
# 귀무가설: 데이터는 등분산성을 갖는다.
# 대립가설: 데이터는 등분산성을 갖지 않는다.
# 유의확률이 0.457 이므로 귀무가설을 채택한다.
(1.013633765449306, 0.4573298588100055)
영향치(influential): 설명변수 관측값 범위를 벗어났으며 적합 회귀선 상에 있는 관측값
이상치(outlier): 설명변수 관측치 범위 내에 존재하며 적합 회귀선에서 벗어난 관측값
import statsmodels.stats.api as sms
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(12,8))
fig = sm.graphics.influence_plot(fit, ax=ax, criterion="cooks")
plt.axhline(2)
plt.axhline(-2)
plt.axvline(4/506)
plt.title('이상치와 영향치')
plt.show()
C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:240: RuntimeWarning: Glyph 51060 missing from current font. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:240: RuntimeWarning: Glyph 49345 missing from current font. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:240: RuntimeWarning: Glyph 52824 missing from current font. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:240: RuntimeWarning: Glyph 50752 missing from current font. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:240: RuntimeWarning: Glyph 50689 missing from current font. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:240: RuntimeWarning: Glyph 54693 missing from current font. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:203: RuntimeWarning: Glyph 51060 missing from current font. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:203: RuntimeWarning: Glyph 49345 missing from current font. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:203: RuntimeWarning: Glyph 52824 missing from current font. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:203: RuntimeWarning: Glyph 50752 missing from current font. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:203: RuntimeWarning: Glyph 50689 missing from current font. C:\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:203: RuntimeWarning: Glyph 54693 missing from current font.
# 산점도 시각화 결과 y-축 값이 +-2를 벗어난 관측치(이상치)와 레버리지 값이 수직선, 4/506 보다 큰 관측치(영향치)가 많이 존재한다.
# 스튜던트 잔차 확인하기
influ = fit.get_influence() # , 영향치 이상치 관련통계량
df.cook = influ.cooks_distance[0] # cook 거리
df.stres = influ.resid_studentized #스튜던트 잔차
df2 = df[(df.stres<2) & (df.stres>-2)] #이상치 제외
df2.shape
# 스튜던트 잔차가 +-2를 넘어가는 이상치를 제외한 데이터 개수는 506개에서 477개로 줄어든다.
C:\Users\THINKP~1\AppData\Local\Temp/ipykernel_5480/120450355.py:5: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access C:\Users\THINKP~1\AppData\Local\Temp/ipykernel_5480/120450355.py:6: UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access
(477, 14)
- 이상치를 제외한 df2 주택가격 = 59.6 - 2.06*학생-교사비율, 결정계수는 25.8%에서 34.3%로 높아졌다. 다시 이상치가 발생할 것이고 이를 제외하면 결정계수는 계속 증가한다.
- 학생-교사비율이 낮을수록 주택가격은 상승한다. 학생교사 비율이 1단위 낮아지면 그 타운 주택가격은 2.06만불 올라간다.
import statsmodels.api as sm
y = df2['PRICE']
X = sm.add_constant(df2['PTRATIO']) #add intercept
fit2 = sm.OLS(y, X).fit()
print(fit2.summary())
OLS Regression Results
==============================================================================
Dep. Variable: PRICE R-squared: 0.343
Model: OLS Adj. R-squared: 0.342
Method: Least Squares F-statistic: 248.4
Date: Thu, 13 Apr 2023 Prob (F-statistic): 2.51e-45
Time: 00:57:41 Log-Likelihood: -1534.3
No. Observations: 477 AIC: 3073.
Df Residuals: 475 BIC: 3081.
Df Model: 1
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 59.6514 2.444 24.408 0.000 54.849 64.454
PTRATIO -2.0622 0.131 -15.762 0.000 -2.319 -1.805
==============================================================================
Omnibus: 4.679 Durbin-Watson: 0.795
Prob(Omnibus): 0.096 Jarque-Bera (JB): 4.465
Skew: 0.226 Prob(JB): 0.107
Kurtosis: 3.141 Cond. No. 165.
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
C:\Anaconda3\lib\site-packages\statsmodels\tsa\tsatools.py:142: FutureWarning: In a future version of pandas all arguments of concat except for the argument 'objs' will be keyword-only
### 다중회귀모형
# 보스턴 주택가격이라는 목표변수에 대한 예측변수로 찰스강 주변 여부를 제외한 측정형 변수 모두를 고려하여 모형추정을 해보자.
import statsmodels.api as sm
y = df['PRICE']
X = sm.add_constant(df.iloc[:,[0,1,2,4,5,6,7,8,9,10,11,12]])
fit = sm.OLS(y, X).fit()
print(fit.summary())
# 추정결과 유의하지 않은 변수를 포함한 추정결과가 출력되었다.
# ( 비소매 상업지 비율 -INDUS, 1940년 이전 건축 주택 비율 -AGE)
# 이런 경우 다중공선성문제가 발생했다고 한다.
# 다중공선성문제?
# 만약 예측변수 간에 상관관계가 높아 유의하다면 OLS 추정과 검정이 쓸모가 없게 되는데 이게 다중공선성 문제라고 한다.
# 예측 변수간의 상관관계가 높다는 것은 변수의 유사성이 높다는 것이고 목표변수를 설명하는 부분이 겹친다는 것.
OLS Regression Results
==============================================================================
Dep. Variable: PRICE R-squared: 0.736
Model: OLS Adj. R-squared: 0.729
Method: Least Squares F-statistic: 114.3
Date: Thu, 13 Apr 2023 Prob (F-statistic): 7.30e-134
Time: 00:57:41 Log-Likelihood: -1503.8
No. Observations: 506 AIC: 3034.
Df Residuals: 493 BIC: 3088.
Df Model: 12
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 36.8920 5.147 7.168 0.000 26.780 47.004
CRIM -0.1131 0.033 -3.417 0.001 -0.178 -0.048
ZN 0.0471 0.014 3.398 0.001 0.020 0.074
INDUS 0.0403 0.062 0.653 0.514 -0.081 0.162
NOX -17.3670 3.851 -4.509 0.000 -24.934 -9.800
RM 3.8505 0.421 9.137 0.000 3.023 4.678
AGE 0.0028 0.013 0.209 0.834 -0.023 0.029
DIS -1.4854 0.201 -7.383 0.000 -1.881 -1.090
RAD 0.3283 0.067 4.934 0.000 0.198 0.459
TAX -0.0138 0.004 -3.653 0.000 -0.021 -0.006
PTRATIO -0.9910 0.131 -7.542 0.000 -1.249 -0.733
B 0.0097 0.003 3.600 0.000 0.004 0.015
LSTAT -0.5342 0.051 -10.459 0.000 -0.635 -0.434
==============================================================================
Omnibus: 190.856 Durbin-Watson: 1.016
Prob(Omnibus): 0.000 Jarque-Bera (JB): 898.352
Skew: 1.619 Prob(JB): 8.42e-196
Kurtosis: 8.668 Cond. No. 1.51e+04
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.51e+04. This might indicate that there are
strong multicollinearity or other numerical problems.
C:\Anaconda3\lib\site-packages\statsmodels\tsa\tsatools.py:142: FutureWarning: In a future version of pandas all arguments of concat except for the argument 'objs' will be keyword-only
# 보스턴 데이터 셋 다시 불러오기
import pandas as pd
from sklearn.datasets import load_boston
boston = load_boston()
df = pd.DataFrame(boston.data, columns=boston.feature_names)
df['target'] = boston.target
df.head()
# 타겟 변수는 'MEDV'.
# 주택가격을 종속 변수로 놓고 어떤 독립 변수를 조합하는 것이 가장 유의미한 모형을 만들 수 있으며 어떤 독립변수가 가장 큰 영향을 가지는지가 알고 싶은것
| CRIM | ZN | INDUS | CHAS | NOX | RM | AGE | DIS | RAD | TAX | PTRATIO | B | LSTAT | target | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.00632 | 18.0 | 2.31 | 0.0 | 0.538 | 6.575 | 65.2 | 4.0900 | 1.0 | 296.0 | 15.3 | 396.90 | 4.98 | 24.0 |
| 1 | 0.02731 | 0.0 | 7.07 | 0.0 | 0.469 | 6.421 | 78.9 | 4.9671 | 2.0 | 242.0 | 17.8 | 396.90 | 9.14 | 21.6 |
| 2 | 0.02729 | 0.0 | 7.07 | 0.0 | 0.469 | 7.185 | 61.1 | 4.9671 | 2.0 | 242.0 | 17.8 | 392.83 | 4.03 | 34.7 |
| 3 | 0.03237 | 0.0 | 2.18 | 0.0 | 0.458 | 6.998 | 45.8 | 6.0622 | 3.0 | 222.0 | 18.7 | 394.63 | 2.94 | 33.4 |
| 4 | 0.06905 | 0.0 | 2.18 | 0.0 | 0.458 | 7.147 | 54.2 | 6.0622 | 3.0 | 222.0 | 18.7 | 396.90 | 5.33 | 36.2 |
import statsmodels.formula.api as sm
from statsmodels.sandbox.regression.predstd import wls_prediction_std
# 모든 변수를 넣고 회귀 분석 수행
#
result = sm.ols(formula = 'target ~ CRIM + ZN + CHAS + NOX + RM + AGE + DIS + RAD + TAX + PTRATIO + B + LSTAT', data = df).fit()
result.summary()
| Dep. Variable: | target | R-squared: | 0.741 |
|---|---|---|---|
| Model: | OLS | Adj. R-squared: | 0.734 |
| Method: | Least Squares | F-statistic: | 117.3 |
| Date: | Thu, 13 Apr 2023 | Prob (F-statistic): | 6.42e-136 |
| Time: | 00:57:41 | Log-Likelihood: | -1498.9 |
| No. Observations: | 506 | AIC: | 3024. |
| Df Residuals: | 493 | BIC: | 3079. |
| Df Model: | 12 | ||
| Covariance Type: | nonrobust |
| coef | std err | t | P>|t| | [0.025 | 0.975] | |
|---|---|---|---|---|---|---|
| Intercept | 36.3639 | 5.091 | 7.143 | 0.000 | 26.361 | 46.366 |
| CRIM | -0.1084 | 0.033 | -3.304 | 0.001 | -0.173 | -0.044 |
| ZN | 0.0459 | 0.014 | 3.368 | 0.001 | 0.019 | 0.073 |
| CHAS | 2.7164 | 0.856 | 3.173 | 0.002 | 1.034 | 4.399 |
| NOX | -17.4295 | 3.681 | -4.735 | 0.000 | -24.662 | -10.197 |
| RM | 3.7970 | 0.416 | 9.132 | 0.000 | 2.980 | 4.614 |
| AGE | 0.0007 | 0.013 | 0.053 | 0.958 | -0.025 | 0.027 |
| DIS | -1.4896 | 0.195 | -7.648 | 0.000 | -1.872 | -1.107 |
| RAD | 0.2999 | 0.064 | 4.710 | 0.000 | 0.175 | 0.425 |
| TAX | -0.0118 | 0.003 | -3.489 | 0.001 | -0.018 | -0.005 |
| PTRATIO | -0.9471 | 0.130 | -7.308 | 0.000 | -1.202 | -0.692 |
| B | 0.0093 | 0.003 | 3.461 | 0.001 | 0.004 | 0.015 |
| LSTAT | -0.5235 | 0.051 | -10.361 | 0.000 | -0.623 | -0.424 |
| Omnibus: | 178.124 | Durbin-Watson: | 1.079 |
|---|---|---|---|
| Prob(Omnibus): | 0.000 | Jarque-Bera (JB): | 784.481 |
| Skew: | 1.521 | Prob(JB): | 4.49e-171 |
| Kurtosis: | 8.287 | Cond. No. | 1.50e+04 |
* Adj.R-squred는 0.734, 모형의 p-value는 0.05 이하로 통계적으로 유의미 함. 그러나 AGE 변수에 대한 P-value가 0.954로 유의미하지 않음 = AGE는 Target에 영향을 주는 변수라고 볼 수 없음.
* AGE를 제외하고 재수행
result = sm.ols(formula = 'target ~ CRIM + ZN + CHAS + NOX + RM + DIS + RAD + TAX + PTRATIO + B + LSTAT', data = df).fit()
result.summary()
| Dep. Variable: | target | R-squared: | 0.741 |
|---|---|---|---|
| Model: | OLS | Adj. R-squared: | 0.735 |
| Method: | Least Squares | F-statistic: | 128.2 |
| Date: | Thu, 13 Apr 2023 | Prob (F-statistic): | 5.54e-137 |
| Time: | 00:57:41 | Log-Likelihood: | -1498.9 |
| No. Observations: | 506 | AIC: | 3022. |
| Df Residuals: | 494 | BIC: | 3072. |
| Df Model: | 11 | ||
| Covariance Type: | nonrobust |
| coef | std err | t | P>|t| | [0.025 | 0.975] | |
|---|---|---|---|---|---|---|
| Intercept | 36.3411 | 5.067 | 7.171 | 0.000 | 26.385 | 46.298 |
| CRIM | -0.1084 | 0.033 | -3.307 | 0.001 | -0.173 | -0.044 |
| ZN | 0.0458 | 0.014 | 3.390 | 0.001 | 0.019 | 0.072 |
| CHAS | 2.7187 | 0.854 | 3.183 | 0.002 | 1.040 | 4.397 |
| NOX | -17.3760 | 3.535 | -4.915 | 0.000 | -24.322 | -10.430 |
| RM | 3.8016 | 0.406 | 9.356 | 0.000 | 3.003 | 4.600 |
| DIS | -1.4927 | 0.186 | -8.037 | 0.000 | -1.858 | -1.128 |
| RAD | 0.2996 | 0.063 | 4.726 | 0.000 | 0.175 | 0.424 |
| TAX | -0.0118 | 0.003 | -3.493 | 0.001 | -0.018 | -0.005 |
| PTRATIO | -0.9465 | 0.129 | -7.334 | 0.000 | -1.200 | -0.693 |
| B | 0.0093 | 0.003 | 3.475 | 0.001 | 0.004 | 0.015 |
| LSTAT | -0.5226 | 0.047 | -11.019 | 0.000 | -0.616 | -0.429 |
| Omnibus: | 178.430 | Durbin-Watson: | 1.078 |
|---|---|---|---|
| Prob(Omnibus): | 0.000 | Jarque-Bera (JB): | 787.785 |
| Skew: | 1.523 | Prob(JB): | 8.60e-172 |
| Kurtosis: | 8.300 | Cond. No. | 1.47e+04 |
- Adj.R-squred는 0.735, 모형의 p-value는 0.05 이하로 모든 변수가 p-value 0.05 이하로 유의미한 결과를 보여줌.
- 변수들 중 질소산화물농도(NOX)가 1 증가 할 때 주택가격의 값이 17이 감소하고 RM은 3.7, CHAS는 2.7 정도 집값 상승에 영향을 준다고 판단 할 수 있음.
회귀분석을 진행하면서 꼭 확인해야 할 부분 3가지 + 검증
#### - 정규성 : 잔차의 분포가 정규분포를 따르는가 #### - 등분산성 : 잔차의 분포가 등분산성을 가지는가 (즉, 고르게 분포하는가) #### - 선형성 : 종속변수와 독립변수가 선형적 관계를 가지는가
df['Price'] = df.target
df.tail()
| CRIM | ZN | INDUS | CHAS | NOX | RM | AGE | DIS | RAD | TAX | PTRATIO | B | LSTAT | target | Price | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 501 | 0.06263 | 0.0 | 11.93 | 0.0 | 0.573 | 6.593 | 69.1 | 2.4786 | 1.0 | 273.0 | 21.0 | 391.99 | 9.67 | 22.4 | 22.4 |
| 502 | 0.04527 | 0.0 | 11.93 | 0.0 | 0.573 | 6.120 | 76.7 | 2.2875 | 1.0 | 273.0 | 21.0 | 396.90 | 9.08 | 20.6 | 20.6 |
| 503 | 0.06076 | 0.0 | 11.93 | 0.0 | 0.573 | 6.976 | 91.0 | 2.1675 | 1.0 | 273.0 | 21.0 | 396.90 | 5.64 | 23.9 | 23.9 |
| 504 | 0.10959 | 0.0 | 11.93 | 0.0 | 0.573 | 6.794 | 89.3 | 2.3889 | 1.0 | 273.0 | 21.0 | 393.45 | 6.48 | 22.0 | 22.0 |
| 505 | 0.04741 | 0.0 | 11.93 | 0.0 | 0.573 | 6.030 | 80.8 | 2.5050 | 1.0 | 273.0 | 21.0 | 396.90 | 7.88 | 11.9 | 11.9 |
%matplotlib inline
matplotlib.style.use('ggplot')
# 산점도 - 우상향 패턴의 데이터
df.plot(kind = 'scatter', x = "RM", y = "Price", figsize=(5, 5), color = 'black', xlim = (4,8), ylim = (10,45))
<AxesSubplot:xlabel='RM', ylabel='Price'>
from sklearn import linear_model #선형 회귀 모델로 학습시키기
# 선형 회귀 모델 생성
linear_regression = linear_model.LinearRegression()
# 선형회귀모델에 필요한 변수 두가지 전달
linear_regression.fit(X = pd.DataFrame(df['RM']), y = df['Price'])
# 모델에 x 값 넣어서 y 값 예측하기
prediction = linear_regression.predict(X = pd.DataFrame(df['RM']))
print('a value: ', linear_regression.intercept_) # 절편
print('b value: ',linear_regression.coef_) # 기울기
a value: -34.67062077643857 b value: [9.10210898]
linear_regression.predict([[50]]) # 방 갯수가 50인 경우 집값이 420민불
array([420.43482828])
### 적합도 검증
residuals = df['Price'] - prediction
residuals.describe()
count 5.060000e+02 mean -8.885295e-15 std 6.609606e+00 min -2.334590e+01 25% -2.547477e+00 50% 8.976267e-02 75% 2.985532e+00 max 3.943314e+01 Name: Price, dtype: float64
SSE = (residuals ** 2).sum()
SST = ((df['Price'] - df['Price'].mean()) ** 2).sum()
R_squared = 1 - (SSE/SST)
print('R_squared: ', R_squared)
R_squared: 0.4835254559913341
df.plot(kind = 'scatter', x = 'RM', y = 'Price', figsize = (6,6), color = 'black',
xlim = (4,8), ylim = (10, 45))
plt.plot(df['RM'], prediction, color = 'b')
[<matplotlib.lines.Line2D at 0x154edc465e0>]
### 성능 평가
from sklearn.metrics import mean_squared_error
print('score: ', linear_regression.score(X = pd.DataFrame(df['RM']), y = df['Price']))
print('Mean Squared Error: ', mean_squared_error(prediction, df['Price']))
print('RMSE: ', mean_squared_error(prediction, df['Price']) ** .5)
score: 0.48352545599133423 Mean Squared Error: 43.60055177116956 RMSE: 6.603071389222561